package com.xcjh.opencv;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.xcjh.opencv.emuns.CommdType;
import com.xcjh.opencv.emuns.MatchImage;
import com.xcjh.opencv.util.CacheUtils;
import com.xcjh.utils.AssertUtils;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.data.repository.init.ResourceReader;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
public class ImageUtil {

    private static final String IMAGE_SUFFIX="bmp";

    /**
     * 是否是图片
     * @param file
     * @return
     */
    public static boolean isPic(String file){
        String suffix = FileUtil.getSuffix(file);
        return IMAGE_SUFFIX.equalsIgnoreCase(suffix);
    }

    /**
     * 缓存图片转OpenCV图片
     */
    public static Mat bufferedImage2Mat(BufferedImage image) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(image,IMAGE_SUFFIX, byteArrayOutputStream);
        byteArrayOutputStream.flush();
        return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.IMREAD_UNCHANGED);
    }


    /**
     * 截取当前屏幕的图片
     * @param robot
     * @return
     * @throws Exception
     */
    public static Mat getScreenImage(Robot robot) throws Exception {
        // 使用 Robot 抓屏,获取屏幕图像
        Rectangle screenSize = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
        BufferedImage screenShot = robot.createScreenCapture(screenSize);

        // 转为 OpenCV 图像
        return ImageUtil.bufferedImage2Mat(screenShot);
    }

    /**
     * 移动并且点击
     * @param mmr
     */
    public static void movePicAndClick(Core.MinMaxLocResult mmr, Robot robot,MatchImage image){
        int x=(int) mmr.minLoc.x;
        int y=(int) mmr.minLoc.y;
        if(image!=null){
            Mat imageFile =getAndSavePic(image.getCode());
            int width = imageFile.width();
            int height = imageFile.height();
            x=x+((int)width/2);
            y=y+((int)height/2);
        }
        ExeRule rule=new ExeRule();
        rule.setRobot(robot);
        // 移动鼠标到相似点位置
        System.out.println("找图移动:x "+x+"  y"+y+"  原始:"+mmr.minLoc.x+" "+mmr.minLoc.y);
        rule.moveTo(x,y);
        //延迟200毫秒
        rule.delay(200);
        rule.leftClick(1);
    }


    /**
     * 执行命令
     *  1. 提取命令, 提取参数
     *  2. 转换参数
     *  3. 生成ExeRule执行对象
     *  4. 调用该对象, 调用 解析出来的命令方法
     * @param command
     * @param robot
     */
    public static void exeRule(String command,Robot robot){
        //注释不执行
        if(command.startsWith("'")||command.startsWith("/")||StrUtil.isEmpty(command)){
            return;
        }
        command=command.replaceAll("\",\"","\"逗号\"");
        //命令提取
        String ml=command.substring(0,command.indexOf(" "));
        //参数提取
        String param=command.substring(command.indexOf(" ")+1);
        //参数转换为真是命令参数
        List<? extends Serializable> paramList = Arrays.stream(param.split(",")).map(o -> {
            String o1=o.replaceAll(" ", "");
            if (o.contains("\"") || o.contains("'")) {
                return o1.replaceAll("\"", "").replaceAll("'", "");
            }
            if (NumberUtil.isNumber(o1)) {
                return NumberUtil.parseInt(o1);
            }
            return null;
        }).collect(Collectors.toList());

        ExeRule rule=new ExeRule();
        rule.setRobot(robot);
        //调用ExeRule命令
        System.out.println(CommdType.findByKey(ml).getMessage()+"  "+JSONUtil.toJsonStr(paramList.toArray()));
        if(!StrUtil.isEmpty(ml)){
            ReflectUtil.invoke(rule,StrUtil.lowerFirst(ml),paramList.toArray());
        }else {
            System.out.println("未执行......");
        }

    }
    public static Core.MinMaxLocResult findImage(MatchImage image, Robot robot) throws Exception {
        return findImage(image.getCode(),robot);//FindSimilarImage.IMAGE_PATH+image.getCode()
    }


    public static Core.MinMaxLocResult findImage(String file,Robot robot) throws Exception {
        //不是bmp标准图片不允许执行
        AssertUtils.isTrue(ImageUtil.isPic(file),"不允许执行非BMP图片");
        String fileName=MatchImage.findByKey(file).getMessage();

        // 加载目标图片和屏幕截图.
        // targetImage=Imgcodecs.imread(file);
        Mat targetImage = getAndSavePic(file);
        Mat screenImage = ImageUtil.getScreenImage(robot);

        // 进行模板匹配
        Mat result = new Mat();
        AssertUtils.isTrue(targetImage.width()>1 && targetImage.height()>1,file+"图片有问题,不能读取,可能是名字错误 含有中文,可能是格式错误.");

        Imgproc.matchTemplate(screenImage, targetImage, result, Imgproc.TM_SQDIFF_NORMED);

        // 分析匹配结果
        Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
        double matchScore = mmr.minVal;
        boolean pass=matchScore < FindSimilarImage.MIN;

        System.out.println("【"+fileName + "】"+new DecimalFormat("#.#############").format(matchScore)+(pass?"    匹配成功":""));
        // 判断是否找到相似图片, 小于阈值就代表找到了, 通过 TM_SQDIFF_NORMED 算法 越小越好.
        if (pass) {
            // 找到了相似图片
            // 进行相关操作，如返回信息、保存、打印等
            return mmr;
        } else {
            // 没有找到相似图片
            // 执行其他处理，如返回空或提示信息等
            return null;
        }
    }

    public static Mat getAndSavePic(String file) {
        return CacheUtils.getOrExeCache(file, CacheUtils.CacheType.PIC, () -> {
            URL resource = ImageUtil.class.getClassLoader().getResource("");
            AssertUtils.isTrue(resource!=null,"找不到路径,请检查环境.在idea下运行 不要打包");
            File classPath=new File(resource.getPath());
            String path=classPath.getParentFile().getParentFile().getAbsolutePath()+"/src/main/resources/picture/";
            String picPath=new File(path+file).getAbsoluteFile().toString();
            System.out.println("初始化图片:"+picPath);
            return Imgcodecs.imread(picPath);
        });
    }

    public static void main(String[] args) {
        exeRule("MoveTo 950, 996",null);
    }
}
